package com.frank.oj.service.oj.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.frank.model.entity.user.UserInfo;
import com.frank.oj.common.exception.StatusFailException;
import com.frank.oj.common.result.CommonResult;
import com.frank.oj.constant.Constants;
import com.frank.oj.model.vo.ACMRankVO;
import com.frank.oj.model.vo.OIRankVO;
import com.frank.oj.service.entity.user.UserInfoEntityService;
import com.frank.oj.service.entity.user.UserRecordEntityService;
import com.frank.oj.service.oj.RankService;
import com.frank.oj.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author frank
 * @Date 2024/4/17
 */
@Service
public class RankServiceImpl implements RankService {
    @Resource
    private UserRecordEntityService userRecordEntityService;
    @Resource
    private UserInfoEntityService userInfoEntityService;
    @Resource
    private RedisUtils redisUtils;

    private static final long cacheRank = 60; //缓存排名60s

    @Override
    public IPage getRankList(Integer limit, Integer currentPage, String searchUser, Integer type) throws StatusFailException {
        if (currentPage == null || currentPage < 1) currentPage = 1;
        if (limit == null || limit < 1) limit = 30;

        List<String> uidList = null;
        if (!StringUtils.isEmpty(searchUser)) {
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(UserInfo::getUuid);
            queryWrapper.and(wrapper -> wrapper
                    .like(UserInfo::getUsername, searchUser)
                    .or()
                    .like(UserInfo::getNickname, searchUser)
                    .or()
                    .like(UserInfo::getRealname, searchUser));
            queryWrapper.eq(UserInfo::getStatus, 0);

            uidList = userInfoEntityService.list(queryWrapper).stream()
                    .map(UserInfo::getUuid)
                    .collect(Collectors.toList());
        }

        IPage rankList = null;
        if (type.intValue() == Constants.Contest.TYPE_ACM.getCode()) {
            rankList = getACMRankList(limit, currentPage, uidList);
        } else if (type.intValue() == Constants.Contest.TYPE_OI.getCode()) {
            rankList = getOIRankList(limit, currentPage, uidList);
        } else {
            throw new StatusFailException("仅支持ACM、OI排名");
        }
        return rankList;
    }

    private IPage<ACMRankVO> getACMRankList(Integer limit, Integer currentPage, List<String> uidList) {
        IPage<ACMRankVO> data = null;
        if (uidList != null) {
            Page<ACMRankVO> page = new Page<>(currentPage, limit);
            if (uidList.isEmpty()) {
                data = page;
            } else {
                data = userRecordEntityService.getACMRankList(page, uidList);
            }
        } else {
            String key = Constants.Account.ACM_RANK_CACHE.getCode() + "_" + limit + "_" + currentPage;
            data = (IPage<ACMRankVO>) redisUtils.get(key);
            if (data == null) {
                Page<ACMRankVO> page = new Page<>(currentPage, limit);
                data = userRecordEntityService.getACMRankList(page, null);
                redisUtils.set(key, data, cacheRank);
            }
        }
        return data;
    }

    private IPage<OIRankVO> getOIRankList(Integer limit, Integer currentPage, List<String> uidList) {
        IPage<OIRankVO> data = null;
        if (uidList != null) {
            Page<OIRankVO> page = new Page<>(currentPage, limit);
            if (!uidList.isEmpty()) {
                data = userRecordEntityService.getOIRankList(page, uidList);
            } else {
                data = page;
            }
        } else {
            String key = Constants.Account.OI_RANK_CACHE.getCode() + "_" + limit + "_" + currentPage;
            data = (IPage<OIRankVO>) redisUtils.get(key);
            if (data == null) {
                Page<OIRankVO> page = new Page<>(currentPage, limit);
                data = userRecordEntityService.getOIRankList(page, null);
                redisUtils.set(key, data, cacheRank);
            }
        }

        return data;
    }
}
